import { MessageTip } from '@app-cad/common/utils/MessageTip';
import {
  getObject,
  i18n,
  nmAppErrorLog,
  nmAppLog,
  setObject,
} from '@app-nextmesh/common/utils';
import { showLoading } from '@app-nextmesh/components';
import {
  clickChildShowMe,
  getSelfEditKey,
  isOnlyOne,
  makeDefaultForm,
} from '@app-nextmesh/components/Forms/components/utils';
import {
  ConditionType,
  IMenuItem,
  ITreeNode,
  onTreeEventUpdate,
  TreeNodeType,
} from '@app-nextmesh/components/types';
import { documentV2 } from '@app-nextmesh/domain';
import { useProjectStore } from '@app-nextmesh/store/project';
import { useSimulationsStore } from '@app-nextmesh/store/simulations';
import {
  LeftPanelEventType,
  ModelEventType,
  ViewEventType,
} from '@app-nextmesh/types';
import { events } from '@app-nextmesh/utils';
import {
  getEmptyVisualization,
  toLocalSimulation,
  toLocalTask,
  toLocalVisualization,
} from '@app-nextmesh/widgets/LeftPanel/data';
import { getSimulationFormFormat } from '@app-nextmesh/widgets/LeftPanel/SimulationMenus';
import { useCallback, useEffect, useRef, useState } from 'react';
import Draggable from 'react-draggable';
import { ErrorBoundary } from 'react-error-boundary';
import {
  SimulationConditionForm,
  SimulationForm,
  TaskForm,
  TaskMonitorForm,
  TaskResultForm,
  VisualizationDerivedForm,
  VisualizationForm,
  VisualizationPlotForm,
} from '../SettingForms/BusinuessForm';
import './style.scss';

const MIN_LEFT = 225;
export default function SettingPanel() {
  const [left, setLeft] = useState(MIN_LEFT);
  const [showForm, setShowForm] = useState({ show: false, node: null });
  const projectInfo = useProjectStore((state) => state.projectInfo);
  const { simulations, setSimulations } = useSimulationsStore();
  const nodeRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const onResize = (width: number) => {
      setLeft(width);
    };
    events.on(ViewEventType.LeftPanelResize, onResize);
    return () => {
      events.off(ViewEventType.LeftPanelResize, onResize);
    };
  }, []);
  useEffect(() => {
    // 表单显示、隐藏或切换时，都触发事件，清除选中模型
    events.emit(ModelEventType.Clear);
  }, [showForm]);
  useEffect(() => {
    nmAppLog('SettingPanel', 'projectInfo', projectInfo);
    if (!projectInfo) {
      return () => {};
    }
    events.on(LeftPanelEventType.NodeClick, treeNodeClickListener);
    events.on(LeftPanelEventType.MenuClick, menuItemClickListener);
    return () => {
      events.off(LeftPanelEventType.NodeClick, treeNodeClickListener);
      events.off(LeftPanelEventType.MenuClick, menuItemClickListener);
    };
  }, [projectInfo]);
  const getFormIndex = (id: string) => {
    const idSplit = id.split('-');
    const formIndexStr = idSplit[idSplit.length - 1]; // 最后一个是对应表单的index
    let formIndex = parseInt(formIndexStr);
    if (isNaN(formIndex)) {
      formIndex = undefined;
    }
    return formIndex;
  };
  /**
   * 添加仿真参数
   * @param node 节点：添加时为父节点，编辑时为自身节点
   * @param onUpdate 更新节点数据
   * @param isEdit 是否是编辑
   * @param menu 菜单信息
   * @returns 无
   */
  const addSimulationParams = async (
    node: ITreeNode,
    onUpdate: onTreeEventUpdate,
    menu?: IMenuItem,
  ) => {
    // id 格式： f8aca372-f376-431b-8faf-3d64cc862c0e-condition.steps.0.BCs
    const id = node.id;
    // data.menuId 格式： simuCondition-CFD.流体力学C.contacts.SurfaceInteraction
    const menuId = node.menuId;
    if (!id || !menuId) {
      return;
    }
    // 获取表单数据的jsonPath，比如： condition.steps.0.BCs
    let jsonPath: string = undefined;
    const ids = id.split('-');
    if (ids.length > 0) {
      jsonPath = ids[ids.length - 1];
    }
    const jsonFormPath = menuId.split('-')[1];
    // menuValue 取值 BodyForce 等
    const menuValue = menu.value;
    const parentFormFormat = getSimulationFormFormat(jsonFormPath); // CFD.流体力学C.contacts.SurfaceInteraction
    const formFormat = getSimulationFormFormat(`${jsonFormPath}.${menuValue}`); // CFD.流体力学C.contacts.SurfaceInteraction.BodyForce
    if (!formFormat) {
      return;
    }
    const lastPath = jsonFormPath.substring(jsonFormPath.lastIndexOf('.') + 1); // SurfaceInteraction

    // 添加一项新的数据
    const nodeFormData = node.formData;
    let menuObject = getObject(nodeFormData, jsonPath);
    // 生成一个名称
    if (isOnlyOne(parentFormFormat) && menuObject?.length > 0) {
      MessageTip.error(
        i18n.t('fieldOnlyAddOne', {
          field: i18n.t(lastPath),
        }),
      );
      return;
    }
    const count = (menuObject?.length ?? 0) + 1;
    const labelName = `${menuValue}${count}`;
    nmAppLog('===formFormat=======', { labelName, menuValue, formFormat });
    const newForm = {
      name: labelName,
      [ConditionType]: menuValue,
      ...makeDefaultForm(formFormat),
    };
    if (!menuObject) {
      setObject(nodeFormData, jsonPath, []);
      menuObject = getObject(nodeFormData, jsonPath);
    }
    menuObject.push(newForm);
    const rspData = await doRequest(documentV2.updateSimulation(node.formData));
    if (!rspData) {
      return;
    }
    onUpdate(toLocalSimulation(rspData), menu, false);
  };
  const treeNodeClickListener = async (
    data: ITreeNode,
    onUpdate: onTreeEventUpdate,
  ) => {
    nmAppLog('handle tree node click', data);
    setShowForm({ show: false, node: null });
    // 根据data.type显示各自对应的表单页，为空则无表单页
    let resetColorbar = true;
    let fi: number;
    const dataType = data.type;
    if (!dataType) {
      return;
    }
    switch (dataType) {
      case TreeNodeType.Simulation:
        setShowForm({
          show: true,
          node: (
            <SimulationForm
              data={data}
              requestType='update'
              onClose={handleClose}
              // onUpdateTitle={(title) => {
              //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
              //   data.label = title;
              //   onUpdate(data);
              // }}
              onUpdate={(newData, reload) => {
                const findIndex = simulations.findIndex(
                  (simulation) => simulation.uuid === newData.uuid,
                );
                if (findIndex !== -1) {
                  simulations[findIndex] = newData;
                }
                setSimulations([...simulations]);
                onUpdate(toLocalSimulation(newData), null, reload);
              }}
            />
          ),
        });
        break;
      case TreeNodeType.Task:
        setShowForm({
          show: true,
          node: (
            <TaskForm
              data={data}
              onClose={handleClose}
              // onUpdateTitle={(title) => {
              //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
              //   data.label = title;
              //   onUpdate(data);
              // }}
              onUpdate={(newData, reload) => {
                onUpdate(toLocalTask(newData), null, reload);
              }}
            />
          ),
        });
        break;
      case TreeNodeType.TaskMonitor:
        setShowForm({
          show: true,
          node: (
            <TaskMonitorForm
              data={data}
              onClose={handleClose}
              // onUpdateTitle={(title) => {
              //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
              //   data.label = title;
              //   onUpdate(data);
              // }}
              onUpdate={(newData, reload) => {
                onUpdate(toLocalTask(newData), null, reload);
              }}
            />
          ),
        });
        break;
      case TreeNodeType.Result:
        resetColorbar = false;
        setShowForm({
          show: true,
          node: (
            <TaskResultForm
              data={data}
              onClose={handleClose}
              onUpdate={() => {}}
            />
          ),
        });
        break;
      case TreeNodeType.Visualization:
        setShowForm({
          show: true,
          node: (
            <VisualizationForm
              data={data}
              requestType='update'
              onClose={handleClose}
              // onUpdateTitle={(title) => {
              //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
              //   data.label = title;
              //   onUpdate(data);
              // }}
              onUpdate={(newData, reload) => {
                onUpdate(newData, null, reload);
              }}
            />
          ),
        });
        break;
      case TreeNodeType.VisualizationDerived:
        // data.id 格式： 7110803301272125440-Derived-0
        fi = getFormIndex(data.id);
        if (fi === undefined) {
          break;
        }
        setShowForm({
          show: true,
          node: (
            <VisualizationDerivedForm
              data={data}
              formIndex={fi}
              onClose={handleClose}
              // onUpdateTitle={(title) => {
              //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
              //   data.label = title;
              //   onUpdate(data);
              // }}
              onUpdate={(newData) => {
                const v = toLocalVisualization(newData);
                onUpdate(v);
              }}
            />
          ),
        });
        break;
      case TreeNodeType.VisualizationPlot:
        // data.id 格式： 7110803301272125440-Plot-0
        fi = getFormIndex(data.id);
        if (fi === undefined) {
          break;
        }
        resetColorbar = false;
        setShowForm({
          show: true,
          node: (
            <VisualizationPlotForm
              data={data}
              formIndex={fi}
              onClose={handleClose}
              // onUpdateTitle={(title) => {
              //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
              //   data.label = title;
              //   onUpdate(data);
              // }}
              onUpdate={(newData) => {
                onUpdate(toLocalVisualization(newData));
              }}
            />
          ),
        });
        break;
      default:
        {
          // 根据dataType动态显示表单页面-编辑
          // dataType 格式： geometry-elementSets
          // data.id 格式： 7110803301272125440-elementSets-0
          // 根据 dataType 判断使用哪个模块的form
          if (dataType.startsWith(TreeNodeType.Simulation)) {
            const names = dataType.split('-')[1]; // Structural.结构力学N.BoundaryType.BodyForce
            let formFormat = getSimulationFormFormat(names);
            if (formFormat == null) {
              return;
            }
            const titleName = names.split('.');
            let formType = titleName[titleName.length - 1];

            // 从id中解析出jsonPath，通过jsonPath获取对应的form
            let jsonPath = data.id.split('-').pop();

            // 找到父节点的formFormat
            const parentFormFormat = getSimulationFormFormat(
              names.substring(0, names.lastIndexOf('.')),
            );
            if (clickChildShowMe(parentFormFormat)) {
              formFormat = parentFormFormat;
              // jsonPath 删除最后一个点及之后的字符，保证和父节点的jsonPath一致
              jsonPath = jsonPath.slice(0, jsonPath.lastIndexOf('.'));
              formType = titleName[titleName.length - 2];
            }
            const selfEditKey = getSelfEditKey(formFormat);
            if (selfEditKey) {
              formFormat = formFormat[selfEditKey];
              jsonPath = jsonPath + '.' + selfEditKey;
            }
            if (!data.hasForm) {
              return;
            }
            setShowForm({
              show: true,
              node: (
                <SimulationConditionForm
                  jsonPath={jsonPath}
                  name={formType}
                  formData={data.formData}
                  formType={formType} // BodyForce
                  formFormat={formFormat}
                  onClose={handleClose}
                  // onUpdateTitle={(title) => {
                  //   // TODO 暂时都不同步更新title，会导致树频繁更新，后续再优化
                  //   data.label = title;
                  //   onUpdate(data);
                  // }}
                  onUpdate={(newData) => {
                    onUpdate(toLocalSimulation(newData));
                  }}
                />
              ),
            });
            break;
          }
        }
        break;
    }
    if (resetColorbar) {
      events.emit(ModelEventType.ResetColorbar);
    }
  };

  const doRequest = async (request: Promise<any>) => {
    const hide = showLoading();
    try {
      return await request;
    } catch (error) {
      nmAppErrorLog('SettingPanel', 'doRequest', error);
    } finally {
      hide();
    }
    return null;
  };

  const showFormForAdd = async (
    data: ITreeNode,
    menu: IMenuItem,
    onUpdate: (newNode: ITreeNode, menu?: IMenuItem, reload?: boolean) => void,
  ) => {
    let resetColorbar = true;
    const dataType = data.type;
    nmAppLog('showFormForAdd:', menu, data, dataType);
    switch (dataType) {
      case TreeNodeType.Visualizations: // 后处理列表添加后处理
        {
          const count = data.children?.length ?? 0;
          const emptyV = getEmptyVisualization(
            projectInfo.uuid,
            `${i18n.t('plot')}${count + 1}`,
          );
          const rspData = await doRequest(documentV2.addPostprocess(emptyV));
          if (!rspData) {
            return;
          }
          const newV = toLocalVisualization(rspData);
          onUpdate(newV, menu, true);
        }
        break;
      case TreeNodeType.Visualization:
        if (menu.value === 'additionPlot') {
          const formData = data.formData;
          const count = formData.plots?.length ?? 0;
          const emptyPlot = {
            name: `${i18n.t('plots')}${count + 1}`,
            source: null,
            colormap: 'jet',
            commands: [],
          };
          if (formData.plots == null) {
            formData.plots = [emptyPlot];
          } else {
            formData.plots.push(emptyPlot);
          }
          const rspData = await doRequest(
            documentV2.updatePostprocess(formData),
          );
          if (!rspData) {
            return;
          }
          const newNode = toLocalVisualization(rspData);
          onUpdate(newNode, menu, false);
          return;
        }
        break;
      case TreeNodeType.VisualizationDerived: // 后处理添加添加派生数据集
        setShowForm({
          show: true,
          node: (
            <VisualizationDerivedForm
              data={data}
              onClose={handleClose}
              onUpdate={(newData) => {
                onUpdate(toLocalVisualization(newData));
              }}
            />
          ),
        });
        break;
      case TreeNodeType.VisualizationPlot: // 后处理添加绘图组
        resetColorbar = false;
        setShowForm({
          show: true,
          node: (
            <VisualizationPlotForm
              data={data}
              onClose={handleClose}
              onUpdate={(newData) => onUpdate(toLocalVisualization(newData))}
            />
          ),
        });
        break;
    }
    if (resetColorbar) {
      events.emit(ModelEventType.ResetColorbar);
    }
  };
  const showFormDynamic = async (
    data: ITreeNode,
    menu: IMenuItem,
    onUpdate: onTreeEventUpdate,
  ) => {
    const resetColorbar = true;
    // 根据data.type、data.menuId和menuItem.value，动态显示表单页面-添加
    // data.type 格式： simulation-boundaries
    const dataType = data.type;
    nmAppLog('showFormDynamic', { dataType });
    if (!dataType) {
      return;
    }
    // data.menuId 格式： Structural-BoundaryType
    const menuId = data.menuId;
    if (!menuId) {
      return;
    }
    // 根据 dataType 判断使用哪个模块的form
    if (dataType.startsWith(TreeNodeType.Simulation)) {
      await addSimulationParams(data, onUpdate, menu);
    }
    if (resetColorbar) {
      events.emit(ModelEventType.ResetColorbar);
    }
  };
  const menuItemClickListener = async (
    data: ITreeNode,
    menu: IMenuItem,
    onUpdate: onTreeEventUpdate,
  ) => {
    setShowForm({ show: false, node: null });
    nmAppLog('menuItemClickListener:', menu, data);
    const menuValue = menu.value;
    switch (menuValue) {
      case 'addition':
      case 'additionSet':
      case 'additionPlot':
      case 'Node':
      case 'Element':
      case 'Surface':
      case 'ReferPoint':
      case 'addSimulations':
        await showFormForAdd(data, menu, onUpdate);
        break;
      case 'delete':
        // 在 Dialogs 中处理删除逻辑
        return;
      default:
        await showFormDynamic(data, menu, onUpdate);
        break;
    }
  };
  const handleClose = useCallback(
    () => setShowForm({ show: false, node: null }),
    [],
  );
  return (
    <Draggable
      handle={'.nm-toolbar'}
      nodeRef={nodeRef}
    >
      <div
        ref={nodeRef}
        id='nm-appFrame-settingsContainer'
        className='nm-appFrame__settingsPanel nm-appFrame-panel'
        style={{ position: 'absolute', left: `${left}px`, marginLeft: '80px' }}
      >
        {showForm.show ? (
          <ErrorBoundary
            fallback={<div>表单加载失败</div>}
            onError={() => {
              setShowForm({ show: false, node: null });
            }}
          >
            {showForm.node}
          </ErrorBoundary>
        ) : (
          <></>
        )}
      </div>
    </Draggable>
  );
}
